﻿using System;
using System.Collections.Generic;
using System.Text.RegularExpressions;
using System.Web;
using System.Web.Caching;
using System.Xml.Serialization;
using CY_MVC.Core;
using CY_MVC.Utility;

namespace CY_MVC.UrlRewrite
{
    #region UrlRemapHelper

    /// <summary>
    /// UrlRemap工具类
    /// 要在web.config的AppSettings里面设置字段UrlRemapRulesPath为UrlRemap规则的路径
    /// </summary>
    public static class UrlRemapHelper
    {
        public static List<UrlRemapRule> UrlRemapRules = new List<UrlRemapRule>();

        public static void Init()
        {
            if (!string.IsNullOrEmpty(StaticConfig.UrlRemapRulesPath))
            {
                UrlRemapRules = XmlDataHelper.LoadFile<List<UrlRemapRule>>(StaticConfig.UrlRemapRulesPath) ??
                                new List<UrlRemapRule>();
            }
        }

        public static void SetRulesList(IEnumerable<UrlRemapRule> p_UrlRemapRules)
        {
            if (p_UrlRemapRules == null)
            {
                throw new Exception("网址重载列表为空!");
            }
            UrlRemapRules = new List<UrlRemapRule>(p_UrlRemapRules);
            SetRulesList();
        }

        public static void SetRulesList()
        {
            if (UrlRemapRules == null)
            {
                throw new Exception("网址重载列表为空!");
            }
            XmlDataHelper.SaveFile(UrlRemapRules, StaticConfig.UrlRemapRulesPath);
        }

        internal static void Remap(object p_Sender, EventArgs p_E)
        {
            var Context = ((HttpApplication)p_Sender).Context;
            var ShowUrl = Context.Request.Path;
            string RealUrl;
            if (!DataCache.GetCache("CY_MVC.UrlRewrite.UrlRemapHelper" + ShowUrl.ToLowerInvariant(), out RealUrl))
            {
                RealUrl = string.Empty;
                foreach (var Item in UrlRemapRules)
                {
                    var RegexStr = "^" + WebUrl.ResolveUrl(HttpContext.Current.Request.ApplicationPath, Item.ShowUrl.Replace(".", "\\u002E")) + "(|/)$";
                    var RegexUrl = new Regex(RegexStr, RegexOptions.IgnoreCase | RegexOptions.Compiled | RegexOptions.Singleline);
                    if (!RegexUrl.IsMatch(ShowUrl)) continue;
                    RealUrl = RegexUrl.Replace(ShowUrl, WebUrl.ResolveUrl(Context.Request.ApplicationPath, Item.RealUrl));
                    if (Item.Stop)
                    {
                        break;
                    }
                }
                DataCache.SetCache("CY_MVC.UrlRewrite.UrlRemapHelper" + ShowUrl.ToLowerInvariant(), RealUrl, Cache.NoAbsoluteExpiration, TimeSpan.FromMinutes(30), CacheItemPriority.AboveNormal);
            }
            if (!string.IsNullOrEmpty(RealUrl))
            {
                RemapUrl(Context, RealUrl);
            }
        }

        /// <summary>
        /// RemapUrl's a URL using <b>HttpContext.RemapUrl()</b>.
        /// </summary>
        /// <param name="p_Context">The HttpContext object to remap the URL to.</param>
        /// <param name="p_RemapUrl">The URL to remap to.</param>
        internal static void RemapUrl(HttpContext p_Context, string p_RemapUrl)
        {
            var uri = new Uri(p_Context.Request.Url.Scheme + "://" + p_Context.Request.Url.Authority + p_RemapUrl);
            p_Context.RewritePath(uri.AbsolutePath, String.Empty, string.IsNullOrEmpty(uri.Query) ? string.Empty : uri.Query.Substring(1, uri.Query.Length - 1));
            var ControllerName = WebUrl.ControllerName(p_Context);
            var handler = ControllerContext.GetController(ControllerName);
            if (handler != null)
            {
                p_Context.RemapHandler(handler);
            }
        }
    }

    #endregion

    #region UrlRemapRule
    //UrlRewrite规则
    [Serializable]
    [XmlRoot]
    public class UrlRemapRule
    {
        private string m_ShowUrl;
        private string m_RealUrl;
        private bool m_Stop;

        [XmlAttribute]
        public string ShowUrl
        {
            get { return m_ShowUrl; }
            set { m_ShowUrl = value; }
        }

        [XmlAttribute]
        public string RealUrl
        {
            get { return m_RealUrl; }
            set { m_RealUrl = value; }
        }

        [XmlAttribute]
        public bool Stop
        {
            get { return m_Stop; }
            set { m_Stop = value; }
        }
    }

    #endregion
}
